<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>part2_8_arm_dvfs_support - learning-gem5</title>
        <!-- Custom HTML head -->
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../favicon.svg">
        <link rel="shortcut icon" href="../favicon.png">
        <link rel="stylesheet" href="../css/variables.css">
        <link rel="stylesheet" href="../css/general.css">
        <link rel="stylesheet" href="../css/chrome.css">
        <link rel="stylesheet" href="../css/print.css" media="print">
        <!-- Fonts -->
        <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../fonts/fonts.css">
        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../highlight.css">
        <link rel="stylesheet" href="../tomorrow-night.css">
        <link rel="stylesheet" href="../ayu-highlight.css">

        <!-- Custom theme stylesheets -->
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="../part0_introduction.html">Learning gem-5</a></li><li class="chapter-item expanded "><a href="../part0_introduction.html"><strong aria-hidden="true">1.</strong> part0_introduction</a></li><li class="chapter-item expanded "><a href="../part1/part1_1_building.html"><strong aria-hidden="true">2.</strong> part1</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part1/part1_1_building.html"><strong aria-hidden="true">2.1.</strong> part1_1_building</a></li><li class="chapter-item expanded "><a href="../part1/part1_2_simple_config.html"><strong aria-hidden="true">2.2.</strong> part1_2_simple_config</a></li><li class="chapter-item expanded "><a href="../part1/part1_3_cache_config.html"><strong aria-hidden="true">2.3.</strong> part1_3_cache_config</a></li><li class="chapter-item expanded "><a href="../part1/part1_4_gem5_stats.html"><strong aria-hidden="true">2.4.</strong> part1_4_gem5_stats</a></li><li class="chapter-item expanded "><a href="../part1/part1_5_gem5_example_configs.html"><strong aria-hidden="true">2.5.</strong> part1_5_gem5_example_configs</a></li><li class="chapter-item expanded "><a href="../part1/part1_6_extending_configs.html"><strong aria-hidden="true">2.6.</strong> part1_6_extending_configs</a></li></ol></li><li class="chapter-item expanded "><a href="../part2/part2_0_environment.html"><strong aria-hidden="true">3.</strong> part2</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part2/part2_0_environment.html"><strong aria-hidden="true">3.1.</strong> part2_0_environment</a></li><li class="chapter-item expanded "><a href="../part2/part2_1_helloobject.html"><strong aria-hidden="true">3.2.</strong> part2_1_helloobject</a></li><li class="chapter-item expanded "><a href="../part2/part2_2_debugging.html"><strong aria-hidden="true">3.3.</strong> part2_2_debugging</a></li><li class="chapter-item expanded "><a href="../part2/part2_3_events.html"><strong aria-hidden="true">3.4.</strong> part2_3_events</a></li><li class="chapter-item expanded "><a href="../part2/part2_4_parameters.html"><strong aria-hidden="true">3.5.</strong> part2_4_parameters</a></li><li class="chapter-item expanded "><a href="../part2/part2_5_memoryobject.html"><strong aria-hidden="true">3.6.</strong> part2_5_memoryobject</a></li><li class="chapter-item expanded "><a href="../part2/part2_6_simplecache.html"><strong aria-hidden="true">3.7.</strong> part2_6_simplecache</a></li><li class="chapter-item expanded "><a href="../part2/part2_7_arm_power_modelling.html"><strong aria-hidden="true">3.8.</strong> part2_7_arm_power_modelling</a></li><li class="chapter-item expanded "><a href="../part2/part2_8_arm_dvfs_support.html" class="active"><strong aria-hidden="true">3.9.</strong> part2_8_arm_dvfs_support</a></li></ol></li><li class="chapter-item expanded "><a href="../part3/part3_00_MSIntro.html"><strong aria-hidden="true">4.</strong> part3</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part3/part3_00_MSIntro.html"><strong aria-hidden="true">4.1.</strong> part3_00_MSIntro</a></li><li class="chapter-item expanded "><a href="../part3/part3_01_cache-intro.html"><strong aria-hidden="true">4.2.</strong> part3_01_cache-intro</a></li><li class="chapter-item expanded "><a href="../part3/part3_02_cache-declarations.html"><strong aria-hidden="true">4.3.</strong> part3_02_cache-declarations</a></li><li class="chapter-item expanded "><a href="../part3/part3_03_cache-in-ports.html"><strong aria-hidden="true">4.4.</strong> part3_03_cache-in-ports</a></li><li class="chapter-item expanded "><a href="../part3/part3_04_cache_actions.html"><strong aria-hidden="true">4.5.</strong> part3_04_cache_actions</a></li><li class="chapter-item expanded "><a href="../part3/part3_05_cache_transitions.html"><strong aria-hidden="true">4.6.</strong> part3_05_cache_transitions</a></li><li class="chapter-item expanded "><a href="../part3/part3_06_directory.html"><strong aria-hidden="true">4.7.</strong> part3_06_directory</a></li><li class="chapter-item expanded "><a href="../part3/part3_07_MSIbuilding.html"><strong aria-hidden="true">4.8.</strong> part3_07_MSIbuilding</a></li><li class="chapter-item expanded "><a href="../part3/part3_08_configuration.html"><strong aria-hidden="true">4.9.</strong> part3_08_configuration</a></li><li class="chapter-item expanded "><a href="../part3/part3_09_running.html"><strong aria-hidden="true">4.10.</strong> part3_09_running</a></li><li class="chapter-item expanded "><a href="../part3/part3_10_MSIdebugging.html"><strong aria-hidden="true">4.11.</strong> part3_10_MSIdebugging</a></li><li class="chapter-item expanded "><a href="../part3/part3_11_simple-MI_example.html"><strong aria-hidden="true">4.12.</strong> part3_11_simple-MI_example</a></li></ol></li><li class="chapter-item expanded "><a href="../part4_gem5_101.html"><strong aria-hidden="true">5.</strong> part4_gem5_101</a></li><li class="chapter-item expanded "><a href="../http://doxygen.gem5.org/develop/index.html"><strong aria-hidden="true">6.</strong> part4_gem5_102</a></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">learning-gem5</h1>

                    <div class="right-buttons">
                        <a href="../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="arm-dvfs-建模"><a class="header" href="#arm-dvfs-建模">ARM DVFS 建模</a></h1>
<p>与大多数现代 CPU 一样，ARM CPU 支持 DVFS。可以对此进行建模，例如，在 gem5 中监控由此产生的功耗。DVFS 建模是通过使用时钟对象的两个组件完成的：电压域和时钟域。本章详细介绍了不同的组件，并展示了将它们添加到现有模拟中的不同方法。</p>
<h2 id="电压域vd"><a class="header" href="#电压域vd">电压域（VD）</a></h2>
<p>电压域决定了 CPU 可以使用的电压值。如果在 gem5 中运行完整系统模拟时未指定 VD，则使用默认值 1.0 伏。这是为了避免在用户对模拟电压不感兴趣时强迫他们考虑电压。</p>
<p>电压域可以从单个值或值列表构造，使用<code>voltage</code>kwarg传递给<code>VoltageDomain</code>构造函数。如果指定了单个值和多个频率，则电压用于时钟域中的所有频率。如果指定了电压值列表，则其条目数必须与相应时钟域中的条目数匹配，并且条目必须按<em>降序</em> 排列。与真实硬件一样，电压域适用于整个处理器插槽。这意味着，如果您想为不同的处理器使用不同的 VD（例如，对于 big.LITTLE 设置），您需要确保 big 和 LITTLE 集群位于不同的套接字上（检查与集群关联的<code>socket_id</code>值）。</p>
<p>有两种方法可以将 VD 添加到现有 CPU/仿真中，一种更灵活，另一种更直接。第一种方法向提供的<code>configs/example/arm/fs_bigLITTLE.py</code>文件添加命令行标志，而第二种方法添加自定义类。</p>
<ol>
<li>
<p>将电压域添加到仿真中的最灵活方法是使用命令行标志。要添加命令行标志，请<code>addOptions</code> 在文件中找到该函数并在那里添加标志，可以选择使用一些帮助文本。</p>
<p>支持单电压和多电压的示例：</p>
<pre><code class="language-python">def addOptions(parser):
    [...]
    parser.add_argument(&quot;--big-cpu-voltage&quot;, nargs=&quot;+&quot;, default=&quot;1.0V&quot;,
                        help=&quot;Big CPU voltage(s).&quot;)
    return parser
</code></pre>
<p><code>nargs=&quot;+&quot;</code>确保至少需要一个参数</p>
<p>然后可以指定电压域值</p>
<pre><code class="language-bash">--big-cpu-voltage &lt;val1&gt;V [&lt;val2&gt;V [&lt;val3&gt;V [...]]]
</code></pre>
<p>这些参数可以在<code>build</code>函数中使用 <code>options.big_cpu_voltage</code>访问。示例用法<code>build</code>：</p>
<pre><code class="language-python">def build(options):
    [...]
    # big cluster
    if options.big_cpus &gt; 0:
        system.bigCluster = big_model(system, options.big_cpus,
                                      options.big_cpu_clock,
                                      options.big_cpu_voltage)
    [...]
</code></pre>
<p><code>build</code>可以添加类似的标志和函数的附加功能，以支持为 LITTLE CPU 指定电压值。这种方法允许非常容易地指定和修改电压。这种方法的唯一缺点是多个命令行参数，有些是列表形式，可能会使用于调用模拟器的命令变得混乱。</p>
</li>
<li>
<p>指定电压域的不太灵活的方法是创建<code>CpuCluster</code>的子类。 与现有<code>BigCluster</code>和 <code>LittleCluster</code>子类类似，这将扩展<code>CpuCluster</code>类。在子类的构造函数中，除了指定 CPU 类型之外，我们还为电压域定义了一个值列表，并使用<code>cpu_voltage</code> kwarg将其传递给对<code>super</code>构造函数的调用。这是一个示例，用于向<code>BigCluster</code>添加电压：</p>
<pre><code class="language-python">class VDBigCluster(devices.CpuCluster):
    def __init__(self, system, num_cpus, cpu_clock=None, cpu_voltage=None):
        # use the same CPU as the stock BigCluster
        abstract_cpu = ObjectList.cpu_list.get(&quot;O3_ARM_v7a_3&quot;)
        # voltage value(s)
        my_voltages = [ '1.0V', '0.75V', '0.51V']

        super(VDBigCluster, self).__init__(
            cpu_voltage=my_voltages,
            system=system,
            num_cpus=num_cpus,
            cpu_type=abstract_cpu,
            l1i_type=devices.L1I,
            l1d_type=devices.L1D,
            wcache_type=devices.WalkCache,
            l2_type=devices.L2
        )
</code></pre>
<p>类似地，可以通过定义<code>VDLittleCluster</code>类来向<code>LittleCluster</code>增加电压参数。
定义了子类后，我们还需要在<code>cpu_types</code>字典中添加一个条目 ，指定一个字符串名称作为键和一对类作为值，例如：</p>
<pre><code class="language-python">cpu_types = {
    [...]
    &quot;vd-timing&quot; : (VDBigCluster, VDLittleCluster)
}
</code></pre>
<p>然后可以通过传递使用带有 VD 的 CPU</p>
<pre><code class="language-bash">--cpu-type vd-timing
</code></pre>
<p>到调用模拟的命令。
由于对电压值的任何修改都必须通过找到正确的子类并修改其代码或添加更多子类和 <code>cpu_types</code>条目来完成，因此这种方法比基于标志的方法少了很多灵活性。</p>
</li>
</ol>
<h2 id="时钟域cd"><a class="header" href="#时钟域cd">时钟域（CD）</a></h2>
<p>电压域与时钟域可以结合使用。如前所述，如果未指定自定义电压值，则时钟域中的所有值均使用默认值 1.0V。</p>
<p>与电压域相比，时钟域的类型有3种（来自 <code>src/sim/clock_domain.hh</code>）：</p>
<ul>
<li><code>ClockDomain</code>– 为绑定在同一时钟域下的一组时钟对象提供时钟。CD 依次按电压域分组。CD 为具有“源（Src）”和“派生（Derived）”时钟域的分层结构提供支持。</li>
<li><code>SrcClockDomain</code>– 描述了连接到可调时钟源的CD。它维护时钟周期并提供设置/获取时钟的方法，以及处理程序将要管理的 CD 的配置参数。这包括各种性能级别的频率值、域 ID 和当前性能级别。请注意，软件要求的性能级别对应于 CD 可以运行的频率之一。</li>
<li><code>DerivedClockDomain</code>-描述了连接到父CD的CD，父CD可以是<code>SrcClockDomain</code>或<code>DerivedClockDomain</code>。它维护时钟分频器并提供获取时钟的方法。</li>
</ul>
<h2 id="向现有仿真添加时钟域"><a class="header" href="#向现有仿真添加时钟域">向现有仿真添加时钟域</a></h2>
<p>这个例子将使用提供VD示例的文件，即 <code>configs/example/arm/fs_bigLITTLE.py</code>和<code>configs/example/arm/devices.py</code>。</p>
<p>与 VD 一样，CD 可以是单个值或值列表。如果给出了时钟速度列表，则适用于提供给 VD 的电压列表的相同规则，即 CD 中的值的数量必须与 VD 中的值的数量相匹配；并且时钟速度必须<em>按降序</em>给出。提供的文件支持将时钟指定为单个值（通过<code>--{big,little}-cpu-clock</code>标志），但不支持将时钟指定为值列表。扩展/修改所提供标志的行为是添加对多值 CD 支持的最简单、最灵活的方法，但也可以通过添加子类来实现。</p>
<ol>
<li>
<p>要向现有<code>--{big,little}-cpu-clock</code>标志添加多值支持，需要在<code>configs/example/arm/fs_bigLITTLE.py</code>中找到<code>addOptions()</code>函数。在大量<code>parser.add_argument</code>调用中，找到添加CPU时钟标志的那些，并把<code>type=str</code>替换成<code>nargs=&quot;+&quot;</code>:</p>
<pre><code class="language-python">def addOptions(parser):
    [...]
    parser.add_argument(&quot;--big-cpu-clock&quot;, nargs=&quot;+&quot;, default=&quot;2GHz&quot;,
                        help=&quot;Big CPU clock frequency.&quot;)
    parser.add_argument(&quot;--little-cpu-clock&quot;, nargs=&quot;+&quot;, default=&quot;1GHz&quot;,
                        help=&quot;Little CPU clock frequency.&quot;)
    [...]
</code></pre>
<p>这样，可以类似于用于 VD 的标志来指定多个频率：</p>
<pre><code class="language-bash">--{big,little}-cpu-clock &lt;val1&gt;GHz [&lt;val2&gt;MHz [&lt;val3&gt;MHz [...]]]
</code></pre>
<p>由于这会修改现有标志，因此标志的值已经连接到<code>build</code>函数中的相关构造函数和 kwargs ，因此无需修改任何内容。</p>
</li>
<li>
<p>在子类中添加 CD 的过程与将 VD 添加为子类的过程非常相似。不同之处在于我们指定时钟频率并在调用父类（构造）函数时用kwarg <code>cpu_voltage</code>传入。</p>
<pre><code class="language-python">class CDBigCluster(devices.CpuCluster):
    def __init__(self, system, num_cpus, cpu_clock=None, cpu_voltage=None):
        # use the same CPU as the stock BigCluster
        abstract_cpu = ObjectList.cpu_list.get(&quot;O3_ARM_v7a_3&quot;)
        # clock value(s)
        my_freqs = [ '1510MHz', '1000MHz', '667MHz']

        super(VDBigCluster, self).__init__(
            cpu_clock=my_freqs,
            system=system,
            num_cpus=num_cpus,
            cpu_type=abstract_cpu,
            l1i_type=devices.L1I,
            l1d_type=devices.L1D,
            wcache_type=devices.WalkCache,
            l2_type=devices.L2
        )
</code></pre>
<p>这可以与 VD 示例结合使用，以便为集群指定 VD 和 CD。
与使用这种方法添加 VD 一样，您需要为要使用的每个 CPU 类型定义一个类，并在<code>cpu_types</code>字典中指定它们的 name-cpuPair 值。这种方法也有同样的限制，而且比基于标志的少了很多灵活性。</p>
</li>
</ol>
<h2 id="确保-cd-具有有效的-domainid"><a class="header" href="#确保-cd-具有有效的-domainid">确保 CD 具有有效的 DomainID</a></h2>
<p>无论使用之前的哪种方法，都需要进行一些额外的修改。这些涉及提供的 <code>configs/example/arm/devices.py</code>文件。</p>
<p>在文件中，找到<code>CpuClusters</code>类并找到 <code>self.clk_domain</code>初始化为<code>SrcClockDomain</code>的位置. 如上述评论中<code>SrcClockDomain</code>所述，它们具有域 ID。如果未设置，则将使用默认 ID <code>-1</code>。以下代码可以确保CD设置了域 ID：</p>
<pre><code class="language-python">[...]
self.clk_domain = SrcClockDomain(clock=cpu_clock,
                                 voltage_domain=self.voltage_domain,
                                 domain_id=system.numCpuClusters())
[...]
</code></pre>
<p>由于CD适用于整个群集，这里使用<code>system.numCpuClusters()</code>。其中，0代表第一簇，1代表第二簇，以此类推。</p>
<p>如果不设置域 ID，则在尝试运行具有 DVFS 功能的模拟时将出现以下错误，因为某些内部检查会捕获默认域 ID：</p>
<pre><code class="language-python">fatal: fatal condition domain_id == SrcClockDomain::emptyDomainID occurred:
DVFS: Controlled domain system.bigCluster.clk_domain needs to have a properly
assigned ID.
</code></pre>
<h2 id="dvfs-处理程序"><a class="header" href="#dvfs-处理程序">DVFS 处理程序</a></h2>
<p>如果您指定 VD 和 CD，然后尝试运行您的模拟，它很可能会运行，但您可能会在输出中注意到以下警告：</p>
<pre><code class="language-bash">warn: Existing EnergyCtrl, but no enabled DVFSHandler found.
</code></pre>
<p>VD 和 CD 已添加，但系统无法与之交互以调整值，因为还没有指定<code>DVFSHandler</code>。解决此问题的最简单方法是在<code>configs/example/arm/fs_bigLITTLE.py</code>文件中添加另一个命令行标志。</p>
<p>在 VD 和 CD 示例中，找到<code>addOptions</code>函数并将以下代码加入：</p>
<pre><code class="language-python">def addOptions(parser):
    [...]
    parser.add_argument(&quot;--dvfs&quot;, action=&quot;store_true&quot;,
                        help=&quot;Enable the DVFS Handler.&quot;)
    return parser
</code></pre>
<p>然后，找到<code>build</code>函数并将此代码加入：</p>
<pre><code class="language-python">def build(options):
    [...]
    if options.dvfs:
        system.dvfs_handler.domains = [system.bigCluster.clk_domain,
                                       system.littleCluster.clk_domain]
        system.dvfs_handler.enable = options.dvfs

    return root
</code></pre>
<p>现在，您现在应该能够通过<code>--dvfs</code>在调用模拟时使用标志来运行支持 DVFS的模拟，并可以根据需要指定大集群和小集群的电压和频率工作点。</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../part2/part2_7_arm_power_modelling.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                            <a rel="next" href="../part3/part3_00_MSIntro.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../part2/part2_7_arm_power_modelling.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                    <a rel="next" href="../part3/part3_00_MSIntro.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>

        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
        <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
    </body>
</html>
